package egar

import (
	"log"
	"sync/atomic"
	"time"
)

type GameState = int32

const (
	// 创建完成，等待运行
	GameStateReady GameState = iota

	// 本局游戏运行中
	GameStateRunning

	// 游戏暂停中
	GameStatePaused

	// 本局游戏结束，等待再次运行下局游戏
	GameStateEnd

	// 游戏销毁
	GameStateShutdown
)

type Game struct {
	state      GameState
	config     *GameConfig
	gameMap    *GameMap
	server     *GameServer
	updateTime int64 // millseconds timestemp
	tickCount  uint64
}

func NewGame(configFileName string) *Game {
	game := &Game{
		state:  GameStateReady,
		config: loadGameConfig(configFileName),
	}
	game.gameMap = newGameMap(game)
	game.server = NewGameServer(game)
	return game
}

func (g *Game) State() GameState {
	return atomic.LoadInt32(&g.state)
}

func (g *Game) Shutdown() {
	atomic.StoreInt32(&g.state, GameStateShutdown)
}

func (g *Game) Run() {
	state := atomic.LoadInt32(&g.state)

	if state == GameStateRunning {
		log.Println("game already running")
		return
	}

	if state == GameStateShutdown {
		log.Println("game already shutdown")
		return
	}

	if state == GameStateReady {
		go g.server.Run()
	}

	g.runLoop()
}

func (g *Game) runLoop() {
	atomic.StoreInt32(&g.state, GameStateRunning)
	g.tickCount = 0
	ticker := time.NewTicker(time.Millisecond * time.Duration(1000/g.config.GameTimeStep))
	lastTime := time.Now()
	for {
		if state := atomic.LoadInt32(&g.state); state != GameStateRunning && state != GameStatePaused {
			break
		}
		t := <-ticker.C
		deltaTime := float64(t.Sub(lastTime).Milliseconds()) / 1000.0
		lastTime = t
		g.mainLoop(deltaTime)
	}
	ticker.Stop()
}

func (g *Game) mainLoop(deltaTime float64) {
	if atomic.LoadInt32(&g.state) == GameStatePaused {
		// do nothing
		return
	}
	g.updateTime = time.Now().UnixMilli()
	g.tickCount++
	g.gameMap.update(g.updateTime, deltaTime)
	g.server.update(g.updateTime, deltaTime)
}
